home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / VideoTelecineRemover.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  13.2 KB  |  550 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <stdlib.h>
  19. #include <crtdbg.h>
  20. #include <math.h>
  21.  
  22. #include "VBitmap.h"
  23. #include "Error.h"
  24. #include "cpuaccel.h"
  25.  
  26. #include "VideoTelecineRemover.h"
  27.  
  28. class CVideoTelecineRemover: public VideoTelecineRemover {
  29. public:
  30.     CVideoTelecineRemover(VBitmap *pInFormat, bool, int, bool);
  31.     ~CVideoTelecineRemover();
  32.  
  33.     void ProcessIn(VBitmap *pIn, long);
  34.     long ProcessOut(VBitmap *pOut);
  35.  
  36. private:
  37.     char *    pMemBlock;
  38.     long    nCombVals[10][2];
  39.     long    lFrameNums[10];
  40.     VBitmap    vb;
  41.     int        nCurrentIn, nCurrentOut;
  42.     int        nCombOffset1, nCombOffset2;
  43.     int        nNewCombOffset1, nNewCombOffset2;
  44.     int        nLag;
  45.     bool    fInvertPolarity, fNewPolarity, fDropMode, fNewDropMode,
  46.             fDecomb, fOffsetLocked;
  47. };
  48.  
  49. VideoTelecineRemover *CreateVideoTelecineRemover(VBitmap *pInFormat, bool fDecomb, int iOffset, bool fInvertedPolarity) {
  50.     return new CVideoTelecineRemover(pInFormat, fDecomb, iOffset, fInvertedPolarity);
  51. }
  52.  
  53.  
  54. CVideoTelecineRemover::CVideoTelecineRemover(VBitmap *pFormat, bool fDecomb, int iOffset, bool fInvertedPolarity) {
  55. //    vb = *pFormat;
  56.  
  57.     vb = VBitmap(NULL, pFormat->w, pFormat->h, 24);
  58.  
  59.     if (!(pMemBlock = new char[vb.size * 10]))
  60.         throw MyMemoryError();
  61.  
  62.     memset(pMemBlock, 0, vb.size * 10);
  63.  
  64.     if (fDecomb) {
  65.         nCurrentIn = 0;
  66.         nLag = 10;
  67.     } else {
  68.         nCurrentIn = 4;
  69.         nLag = 6;
  70.     }
  71.     nCurrentOut = 9;
  72.  
  73.     if (iOffset<0) {
  74.         nCombOffset1 = nNewCombOffset1 = -1;
  75.         nCombOffset2 = nNewCombOffset2 = -1;
  76.         fDropMode = fNewDropMode = true;
  77.         fOffsetLocked = false;
  78.     } else {
  79.         fDropMode = false;
  80.         nCombOffset1 = iOffset;
  81.         nCombOffset2 = (iOffset+1) % 5;
  82.         fInvertPolarity = fInvertedPolarity;
  83.         fOffsetLocked = true;
  84.     }
  85.     this->fDecomb = fDecomb;
  86.  
  87.     memset(nCombVals, 0, sizeof nCombVals);
  88. }
  89.  
  90. VideoTelecineRemover::~VideoTelecineRemover() {
  91. }
  92.  
  93. CVideoTelecineRemover::~CVideoTelecineRemover() {
  94.     delete[] pMemBlock;
  95. }
  96.  
  97. static inline int sq(int d) {
  98.     return d*d;
  99. }
  100.  
  101. #if 0
  102.  
  103. static long __declspec(naked) computeScanImprovementMMX(Pixel8 *src1, Pixel8 *src2, PixOffset pitch, PixDim w) {
  104.     __asm {
  105.         push        ebx
  106.  
  107.         mov            eax,[esp+8]
  108.         mov            ecx,[esp+16]
  109.         mov            edx,[esp+12]
  110.         mov            ebx,[esp+20]
  111.  
  112.         pxor        mm4,mm4
  113. xloop:
  114.         movd        mm0,[eax]
  115.         pxor        mm7,mm7
  116.  
  117.         movd        mm1,[eax+ecx*2]
  118.         punpcklbw    mm0,mm7
  119.  
  120.         movd        mm2,[eax+ecx]
  121.         punpcklbw    mm1,mm7
  122.  
  123.         movd        mm3,[edx]
  124.         punpcklbw    mm2,mm7            ;mm2 = pB
  125.  
  126.         paddw        mm0,mm1            ;mm0 = pA + pC
  127.         paddw        mm2,mm2            ;mm2 = 2*pB
  128.  
  129.         punpcklbw    mm3,mm7            ;mm3 = pD
  130.         psubw        mm2,mm0            ;mm2 = 2*pB - (pA+pC)
  131.  
  132.         paddw        mm3,mm3            ;mm3 = 2*pD
  133.         pmaddwd        mm2,mm2            ;mm2 = sq(2*pB - (pA+pC))
  134.  
  135.         psubw        mm3,mm0            ;mm3 = 2*pD - (pA+pC)
  136.         add            eax,4
  137.  
  138.         pmaddwd        mm3,mm3            ;mm3 = sq(2*pD - (pA+pC))
  139.         add            edx,4
  140.  
  141.         paddd        mm4,mm2
  142.         dec            ebx
  143.  
  144.         ;
  145.         ;
  146.  
  147.         psubd        mm4,mm3
  148.         jne            xloop
  149.  
  150.         movd        eax,mm4
  151.         psrlq        mm4,32
  152.         movd        ecx,mm4
  153.         add            eax,ecx
  154.  
  155.         pop            ebx
  156.         ret
  157.     }
  158. }
  159. #else
  160. static long __declspec(naked) computeScanImprovementMMX(Pixel8 *src1, Pixel8 *src2, PixOffset pitch, PixDim w) {
  161.     __asm {
  162.         push        ebx
  163.  
  164.         mov            eax,[esp+8]
  165.         mov            ecx,[esp+16]
  166.         mov            edx,[esp+12]
  167.         mov            ebx,[esp+20]
  168.  
  169.         pxor        mm6,mm6
  170. xloop:
  171.         movd        mm0,[eax]
  172.         pxor        mm7,mm7
  173.  
  174.         movd        mm1,[eax+ecx*2]
  175.         punpcklbw    mm0,mm7            ;mm0 = pA
  176.  
  177.         movd        mm2,[eax+ecx]
  178.         punpcklbw    mm1,mm7            ;mm1 = pC
  179.  
  180.         movd        mm3,[edx]
  181.         punpcklbw    mm2,mm7            ;mm2 = pB
  182.  
  183.         movd        mm4,[edx+ecx*2]
  184.         punpcklbw    mm3,mm7            ;mm3 = pD
  185.  
  186.         movd        mm5,[edx+ecx]
  187.         punpcklbw    mm4,mm7            ;mm4 = pF
  188.  
  189.         punpcklbw    mm5,mm7            ;mm5 = pE
  190.         paddw        mm0,mm1            ;mm0 = pA + pC
  191.  
  192.         paddw        mm3,mm4            ;mm3 = pD + pF
  193.         paddw        mm5,mm5            ;mm5 = 2*pE
  194.  
  195.         paddw        mm2,mm2            ;mm2 = 2*pB
  196.         psubw        mm3,mm5            ;mm3 = pD + pF - 2*pE
  197.  
  198.         psubw        mm5,mm0            ;mm5 = 2*pE - (pA + pC)
  199.         pmaddwd        mm3,mm3            ;mm3 = sq(pD + pF - 2*pE)    [mm3 --- ---]
  200.  
  201.         psubw        mm0,mm2            ;mm0 = pA + pC - 2*pB
  202.         pmaddwd        mm5,mm5            ;mm5 = sq(pA + pC - 2*pE)    [mm5 mm3 ---]
  203.  
  204.         pmaddwd        mm0,mm0            ;mm0 = sq(pA + pC - 2*pB)    [mm0 mm5 mm3]
  205.         add            eax,4
  206.  
  207.         paddd        mm6,mm3
  208.         add            edx,4
  209.  
  210.         psubd        mm6,mm5
  211.         dec            ebx
  212.  
  213.         paddd        mm6,mm0
  214.         jne            xloop
  215.  
  216.         movd        eax,mm6
  217.         psrlq        mm6,32
  218.         movd        ecx,mm6
  219.         add            eax,ecx
  220.  
  221.         pop            ebx
  222.         ret
  223.     }
  224. }
  225. #endif
  226.  
  227. static long computeScanImprovement(Pixel8 *src1, Pixel8 *src2, PixOffset pitch, PixDim w) {
  228.     long imp = 0;
  229.  
  230.     // now using original intended algorithm, plus checking if the second frame is also combed
  231.     // so it doesn't easily take the frame to be dropped as the frame to be decombed. 
  232.     // Check below to see fix...  This actually works very well! Beats any commercial
  233.     // software out there!
  234.     //
  235.     // Without the fix, the reason the broken algorithm sorta worked is because, in the 
  236.     // sequence [A1/A2] [A1/B2], if A2 sorta looked like B2, it would actually take the 
  237.     // right offset... but when scene changes a lot, this does not work at all. 
  238.     //
  239.     // Samuel Audet <guardia@cam.≤rg>
  240.  
  241.     w = -w;
  242.     do {
  243.         int rA = src1[0];
  244.         int rB = src1[pitch];
  245.         int rC = src1[pitch*2];
  246.         int rD = src2[0];
  247.         int rE = src2[pitch];
  248.         int rF = src2[pitch*2];
  249.  
  250.         imp += sq(rA + rC - 2*rB)        // combing in current frame
  251.             + sq(rD + rF - 2*rE)        // combing in second frame
  252.             - sq(rA + rC - 2*rE);        // combing in merged frame
  253.  
  254.         src1++;
  255.         src2++;
  256.     } while(++w);
  257.  
  258.     return imp;
  259. }
  260.  
  261. void CVideoTelecineRemover::ProcessIn(VBitmap *pIn, long lFrameNum) {
  262.     Pixel8 *src1, *src2;
  263.     PixDim h;
  264.     __int64 field1=0, field2=0;
  265.  
  266.     vb.data = (Pixel *)(pMemBlock + vb.pitch*vb.h * nCurrentIn);
  267.  
  268.     vb.BitBlt(0, 0, pIn, 0, 0, -1, -1);
  269.  
  270.     lFrameNums[nCurrentIn] = lFrameNum;
  271.  
  272.     if (fOffsetLocked) {
  273.         if (++nCurrentIn == 10)
  274.             nCurrentIn = 0;
  275.         return;
  276.     }
  277.  
  278.     // We skip the top and bottom 8 lines -- they're usually full of head noise.
  279.  
  280.     {
  281.         long longs = (vb.w*3)/4;
  282.  
  283.         h = (vb.h-2)/2 - 8;
  284.         src1 = (Pixel8 *)(pMemBlock + vb.pitch*(vb.h * nCurrentIn + 8));
  285.         src2 = (Pixel8 *)(pMemBlock + vb.pitch*(vb.h * ((nCurrentIn+9)%10) + 8));
  286.  
  287.         if (MMX_enabled) {
  288.             do {
  289.                 field1 += computeScanImprovementMMX(src1, src2, vb.pitch, longs);
  290.                 field2 += computeScanImprovementMMX(src1+vb.pitch, src2+vb.pitch, vb.pitch, longs);
  291.  
  292.                 src1 += vb.pitch*2;
  293.                 src2 += vb.pitch*2;
  294.             } while(--h);
  295.  
  296.             __asm emms
  297.         } else {
  298.             do {
  299.                 field1 += computeScanImprovement(src1, src2, vb.pitch, longs*4);
  300.                 field2 += computeScanImprovement(src1+vb.pitch, src2+vb.pitch, vb.pitch, longs*4);
  301.  
  302.                 src1 += vb.pitch*2;
  303.                 src2 += vb.pitch*2;
  304.             } while(--h);
  305.         }
  306.     }
  307.  
  308.     if (field1 < 0)
  309.         field1 = 0;
  310.  
  311.     if (field2 < 0)
  312.         field2 = 0;
  313.  
  314.     _RPT2(0,"%16d %16d\n", (long)sqrt(field1), (long)sqrt(field2));
  315.  
  316.     nCombVals[(nCurrentIn+9)%10][0] = (long)sqrt(field1);
  317.     nCombVals[(nCurrentIn+9)%10][1] = (long)sqrt(field2);
  318.  
  319.     if (++nCurrentIn == 10)
  320.         nCurrentIn = 0;
  321.  
  322.     if (nCurrentIn == 0 || nCurrentIn == 5) {
  323.         int i;
  324.         long best_score = 0;
  325.         int best_offset = -1;
  326.         bool best_polarity = false;
  327.  
  328.         for(i=0; i<5; i++) {
  329.             long v1 = nCombVals[(nCurrentIn+4+i)%10][0];
  330.             long v2 = nCombVals[(nCurrentIn+4+i)%10][1];
  331.  
  332.             if (v1 > best_score) {
  333.                 best_offset = (i+4)%5;
  334.                 best_polarity = true;
  335.                 best_score = v1;
  336.             }
  337.  
  338.             if (v2 > best_score) {
  339.                 best_offset = (i+4)%5;
  340.                 best_polarity = false;
  341.                 best_score = v2;
  342.             }
  343.         }
  344.  
  345.         _RPT4(0,"----------- %d %d [%d %d]\n", best_offset, best_polarity, nNewCombOffset1, fNewPolarity);
  346.  
  347.         fDropMode = fNewDropMode;
  348.         nCombOffset1 = nNewCombOffset1;
  349.         nCombOffset2 = nNewCombOffset2;
  350.         fInvertPolarity = fNewPolarity;
  351.  
  352.         if (best_offset == -1) {
  353.             fNewDropMode = true;
  354.             nNewCombOffset1 = 0;
  355.             nNewCombOffset2 = 1;
  356.         } else {
  357.             fNewDropMode = false;
  358.             nNewCombOffset1 = best_offset;
  359.             nNewCombOffset2 = (best_offset+1) % 5;
  360.             fNewPolarity = best_polarity;
  361.         }
  362.     }
  363. }
  364.  
  365. static void __declspec(naked) DeBlendMMX_32_24(void *dst, void *src1, void *src2, void *src3, void *src4, long w3, long h, long spitch, long dmodulo) {
  366.     static const __int64 one = 0x0001000100010001i64;
  367.     __asm {
  368.         push        ebp
  369.         push        edi
  370.         push        esi
  371.         push        ebx
  372.  
  373.         mov            ebp,[esp+24+16]
  374.         mov            edi,[esp+4+16]
  375.         mov            eax,[esp+8+16]
  376.         mov            ebx,[esp+12+16]
  377.         mov            ecx,[esp+16+16]
  378.         mov            edx,[esp+20+16]
  379.         sub            eax,ebp
  380.         sub            ebx,ebp
  381.         sub            ecx,ebp
  382.         sub            edx,ebp
  383.         pxor        mm7,mm7
  384. yloop:
  385.         mov            ebp,[esp+24+16]
  386. xloop:
  387.         movd        mm0,[eax+ebp]
  388.         movd        mm1,[ebx+ebp]
  389.         movd        mm2,[ecx+ebp]
  390.         movd        mm3,[edx+ebp]
  391.         punpcklbw    mm0,mm7            ;mm0 = A = a
  392.         punpcklbw    mm1,mm7            ;mm1 = B = (a+b)/2
  393.         punpcklbw    mm2,mm7            ;mm2 = C = (b+c)/2
  394.         punpcklbw    mm3,mm7            ;mm3 = D = c
  395.         paddw        mm0,mm3            ;mm0 = A+D = a+c
  396.         paddw        mm1,mm2            ;mm1 = B+C = (a+b)/2 + (b+c)/2 = b + (a+c)/2
  397.         paddw        mm0,one
  398.         psrlw        mm0,1            ;mm0 = (a+c)/2
  399.         psubw        mm1,mm0            ;mm1 = [B1][R0][G0][B0] *done
  400.  
  401.         movd        mm0,[eax+ebp+4]
  402.         movd        mm4,[ebx+ebp+4]
  403.         movd        mm2,[ecx+ebp+4]
  404.         movd        mm3,[edx+ebp+4]
  405.         punpcklbw    mm0,mm7            ;mm0 = A = a
  406.         punpcklbw    mm4,mm7            ;mm4 = B = (a+b)/2
  407.         punpcklbw    mm2,mm7            ;mm2 = C = (b+c)/2
  408.         punpcklbw    mm3,mm7            ;mm3 = D = c
  409.         paddw        mm0,mm3            ;mm0 = A+D = a+c
  410.         paddw        mm4,mm2            ;mm4 = B+C = (a+b)/2 + (b+c)/2 = b + (a+c)/2
  411.         paddw        mm0,one
  412.         psrlw        mm0,1            ;mm0 = (a+c)/2
  413.         psubw        mm4,mm0            ;mm4 = [G2][B2][R1][G1]
  414.  
  415.         movd        mm0,[eax+ebp+8]
  416.         movd        mm5,[ebx+ebp+8]
  417.         movd        mm2,[ecx+ebp+8]
  418.         movd        mm3,[edx+ebp+8]
  419.         punpcklbw    mm0,mm7            ;mm0 = A = a
  420.         punpcklbw    mm5,mm7            ;mm1 = B = (a+b)/2
  421.         punpcklbw    mm2,mm7            ;mm2 = C = (b+c)/2
  422.         punpcklbw    mm3,mm7            ;mm3 = D = c
  423.         paddw        mm0,mm3            ;mm0 = A+D = a+c
  424.         paddw        mm5,mm2            ;mm1 = B+C = (a+b)/2 + (b+c)/2 = b + (a+c)/2
  425.         paddw        mm0,one
  426.         psrlw        mm0,1            ;mm0 = (a+c)/2
  427.         psubw        mm5,mm0            ;mm5 = [R3][G3][B3][R2]
  428.  
  429.         movq        mm6,mm4            ;mm6 = [G2][B2][R1][G1]
  430.         psrlq        mm4,32            ;mm4 = [  ][  ][G2][B2]
  431.  
  432.         psllq        mm6,16            ;mm6 = [B2][R1][G1][  ]
  433.         movq        mm2,mm1            ;mm2 = [B1][R0][G0][B0]
  434.  
  435.         movq        mm0,mm5            ;mm0 = [R3][G3][B3][R2]
  436.         psrlq        mm2,48            ;mm2 = [  ][  ][  ][B1]
  437.  
  438.         psllq        mm5,32            ;mm5 = [B3][R2][  ][  ]
  439.         por            mm2,mm6            ;mm2 = [B2][R1][G1][B1] *done
  440.  
  441.         por            mm4,mm5            ;mm4 = [B3][R2][G2][B2] *done
  442.         packuswb    mm1,mm2            ;mm0 = [B2][R1][G1][B1][B1][R0][G0][B0]
  443.  
  444.         psrlq        mm0,16            ;mm5 = [  ][R3][G3][B3] *done
  445.  
  446.         movq        [edi+0],mm1
  447.         packuswb    mm4,mm0            ;mm4 = [  ][R3][G3][B3][B3][R2][G2][B2]
  448.  
  449.         movq        [edi+8],mm4
  450.  
  451.         add            edi,16
  452.  
  453.         add            ebp,12
  454.         jne            xloop
  455.  
  456.         mov            ebp,[esp+32+16]
  457.         add            edi,[esp+36+16]
  458.         add            eax,ebp
  459.         add            ebx,ebp
  460.         add            ecx,ebp
  461.         add            edx,ebp
  462.  
  463.         dec            dword ptr [esp+28+16]
  464.         jne            yloop
  465.         emms
  466.  
  467.         pop            ebx
  468.         pop            esi
  469.         pop            edi
  470.         pop            ebp
  471.         ret
  472.     }
  473. }
  474.  
  475. long CVideoTelecineRemover::ProcessOut(VBitmap *pOut) {
  476.  
  477.     if (++nCurrentOut >= 10)
  478.         nCurrentOut = 0;
  479.  
  480.     if (nLag) {
  481.         --nLag;
  482.         return -1;
  483.     }
  484.  
  485.     // Input frames:    [A1/A2] [A1/B2] [B1/C2] [C1/C2] [D1/D2]
  486.     // Action:            copy    decomb  drop    copy    copy
  487.  
  488.     if ((nCurrentOut == nCombOffset1 || nCurrentOut == nCombOffset1+5) && !fDropMode) {
  489.         // First combed frame; reconstruct.
  490.  
  491.         if (fDecomb) {
  492.             VBitmap vb_in, vb_out;
  493.  
  494.             // Copy bottom field.
  495.  
  496.             vb_in            = vb;
  497.             vb_in.data        = (Pixel *)(pMemBlock + vb.pitch * (vb.h*((nCurrentOut+(fInvertPolarity?1:0))%10) + (vb.h & 1)));
  498.             vb_in.modulo    += vb.pitch;
  499.             vb_in.pitch        *= 2;
  500.             vb_in.h            = (vb_in.h + 1)/2;
  501.  
  502.             vb_out            = *pOut;
  503.             vb_out.modulo    += vb_out.pitch;
  504.             vb_out.pitch    *= 2;
  505.             vb_out.h        = (vb_out.h + 1)/2;
  506.  
  507.             vb_out.BitBlt(0, 0, &vb_in, 0, 0, -1, -1);
  508.     //        vb_out.RectFill(0, 0, -1, -1, 0x00ff00);
  509.  
  510.             // Copy top field.
  511.  
  512.             vb_in.data        = (Pixel *)(pMemBlock + vb.pitch * (vb.h*((nCurrentOut+(fInvertPolarity?0:1))%10) + 1 - (vb.h & 1)));
  513.             vb_in.h            = vb.h/2;
  514.  
  515.             vb_out.data        = (Pixel *)((char *)pOut->data + pOut->pitch*(1-(pOut->h & 1)));
  516.             vb_out.h        = pOut->h/2;
  517.  
  518.             vb_out.BitBlt(0, 0, &vb_in, 0, 0, -1, -1);
  519.     //        vb_out.RectFill(0, 0, -1, -1, 0xff0000);
  520.         } else {
  521.             _RPT2(0,"Recon: %d %d\n", nCurrentIn, nCurrentOut);
  522.  
  523.             DeBlendMMX_32_24(
  524.                     pOut->data,
  525.                     pMemBlock + vb.pitch * (vb.h * ((nCurrentOut+9)%10)),
  526.                     pMemBlock + vb.pitch * (vb.h *   nCurrentOut       ),
  527.                     pMemBlock + vb.pitch * (vb.h * ((nCurrentOut+1)%10)),
  528.                     pMemBlock + vb.pitch * (vb.h * ((nCurrentOut+2)%10)),
  529.                     -vb.w*3,
  530.                     vb.h,
  531.                     vb.pitch,
  532.                     pOut->modulo);
  533.         }
  534.  
  535.         return lFrameNums[nCurrentOut];
  536.  
  537.     } else if (nCurrentOut == nCombOffset2 || nCurrentOut == nCombOffset2+5) {
  538.         // Second combed frame; drop.
  539.         return -1;
  540.     } else {
  541.         // Uncombed, unduplicated frame.
  542.  
  543.         vb.data = (Pixel *)(pMemBlock + vb.pitch*vb.h * nCurrentOut);
  544.  
  545.         pOut->BitBlt(0, 0, &vb, 0, 0, -1, -1);
  546.  
  547.         return lFrameNums[nCurrentOut];
  548.     }
  549. }
  550.